package com.zuikaku.nettychat.netty.framework;

import com.dyuproject.protostuff.runtime.RuntimeSchema;
import com.zuikaku.nettychat.netty.dto.NettyResponse;
import com.zuikaku.nettychat.netty.handler.MyNettyRequestHandler;
import com.zuikaku.nettychat.netty.vo.MethodType;
import com.zuikaku.nettychat.utils.ConvertTools;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class NettyServer {


    @Value("${netty.port}")
    private int port;


    @Autowired
    private ControllerManager controllerManager;

    @Autowired
    private NettyServer nettyServer;

    private ConcurrentHashMap<SocketChannel,NettyClient> socketChannelNettyClientMap;

    private List<NettyClient> onlineNettyClientList;

    /**
     * 发回响应信息给客户端
     * @param responseData
     * @param methodType
     * @param socketChannel
     */
    public static void sendResponseToClient(String responseData, MethodType methodType, SocketChannel socketChannel) {
        NettyResponse nettyResponse =new NettyResponse();
        nettyResponse.methodType = methodType.getValue();
        nettyResponse.data = responseData;
        //转换为ByteBuff
        ByteBuf byteBuf = ConvertTools.nettyResponseToByteBuff(nettyResponse, RuntimeSchema.getSchema(NettyResponse.class));
        //写入和冲刷
        socketChannel.writeAndFlush(byteBuf);
    }

    public ConcurrentHashMap<SocketChannel, NettyClient> getSocketChannelNettyClientMap() {
        return socketChannelNettyClientMap;
    }

    public List<NettyClient> getOnlineNettyClientList() {
        return onlineNettyClientList;
    }

    public void startServer(){
        socketChannelNettyClientMap = new ConcurrentHashMap<>();
        onlineNettyClientList = new ArrayList<>();

        NioEventLoopGroup bossGroup =null;
        NioEventLoopGroup workerGroup = null;
        try {
            //1创建我们两个线程组，bossGroup，workerGroup
            bossGroup = new NioEventLoopGroup(1);
            workerGroup = new NioEventLoopGroup();
            //2创建服务端启动助手
            ServerBootstrap bootstrap = new ServerBootstrap();
            //3.将线程组设置给启动助手
            bootstrap.group(bossGroup, workerGroup)
                    //4.指定通信channel的类型
                    .channel(NioServerSocketChannel.class)
                    //5.指定channel初始化器
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            //6.自定义业务客户端和自定义handler处理
                            System.out.println("报告：客户端连入，IP："+socketChannel.localAddress().getHostName());
                            //创建业务上的NettyClient
                            NettyClient client =new NettyClient();
                            client.setSocketChannel(socketChannel);
                            //加入到在线客户端列表当中
                            onlineNettyClientList.add(client);
                            //加入到Map
                            socketChannelNettyClientMap.put(socketChannel,client);
                            // 添加自定义处理器
                            socketChannel.pipeline().addLast(new MyNettyRequestHandler(controllerManager,nettyServer));
                        }
                    });
            //7.服务端启动助手绑定端口，并且设置同步方式运行，获得返回的channelFuture对象
            ChannelFuture channelFuture = bootstrap.bind(port).sync();
            System.out.println("--服务开启了--");
            //8.配置channelFuture在未来以同步方式关闭
            channelFuture.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
